#pragma once
#include <string>
#include <memory>
#include <functional>
#include <unordered_map>
#include <iostream>
#include <fcntl.h>
#include <sstream>
#include "tcp_server.hpp"
#include "epoll_intf.hpp"
#include "../common/nocopy.hpp"

class Link;
class LinkManager; //类的前向声明！！！

using func_t = std::function<void(std::shared_ptr<Link>)>;
static const string DEF_IP = "0.0.0.0";
static const uint16_t DEF_PORT = -1;
static const char* TAB8 = "        ";

class Link
{
    friend class LinkManager;
    std::string _inbuf;
    std::string _outbuf;

public:
    
    int _sockfd = -1; //sockfd默认给定-1，表示该链接无效
    // foreign address
    std::string _ip;
    uint16_t _port;
    uint32_t _event;
    func_t _recv_cb;
    func_t _send_cb;
    func_t _except_cb;
    LinkManager& _linkmng;

    Link(int sockfd, uint32_t event, LinkManager& linkmng, const std::string &ip = DEF_IP, uint16_t port = DEF_PORT)
        : _sockfd(sockfd), _event(event), _linkmng(linkmng), _ip(ip), _port(port)
    {
        if (event & EPOLLET)
        {
            SetNonBlock(sockfd); //在ET模式下必须确保fd是非阻塞的
        }
    }

    void SetNonBlock(int sockfd)
    {
        int fl = fcntl(sockfd, F_GETFL);
        if (fl == -1)
        {
            LogMessage(ERROR, "fcntl error! fd: %d", sockfd);
            exit(errno);
        }
        int ret = fcntl(sockfd, F_SETFL, fl | O_NONBLOCK);
        if (ret == -1)
        {
            LogMessage(ERROR, "fcntl error! fd: %d", sockfd);
            exit(errno);
        }
        LogMessage(DEBUG, "set nonblock success! fd %d", sockfd);
    }

    void SetCallBack(func_t recv_cb, func_t send_cb, func_t except_cb)
    {
        _recv_cb = recv_cb;
        _send_cb = send_cb;
        _except_cb = except_cb;
    }

    void ModEvent(uint32_t event); //成员函数的类内声明

    void AppendInbuf(const std::string &content)
    {
        _inbuf += content;
    }

    void AppendOutbuf(const std::string &content)
    {
        _outbuf += content;
    }

    std::string &GetInbuf()
    {
        return _inbuf;
    }

    std::string &GetOutbuf()
    {
        return _outbuf;
    }
};

class LinkManager
{
    friend class Link;

    std::unordered_map<int, std::shared_ptr<Link>> _linkMap;
    Epoller& _epoller;

public:
    LinkManager(Epoller& epoller)
        : _epoller(epoller)
    {
    }

    bool CheckLink(int fd)
    {
        if (_linkMap.find(fd) != _linkMap.end())
            return true;
        else
            return false;
    }

    void Connect(std::shared_ptr<Link> link_ptr)
    {
        int sockfd = link_ptr->_sockfd;
        _epoller.EpollCtrl(EPOLL_CTL_ADD, sockfd, link_ptr->_event);
        _linkMap.insert(make_pair(sockfd, link_ptr));
    }

    void DisConnect(std::shared_ptr<Link> link_ptr)
    {
        int sockfd = link_ptr->_sockfd;
        if (!CheckLink(sockfd))
            return;
        _epoller.EpollCtrl(EPOLL_CTL_DEL, sockfd, NONEVENT); //要在close之前调用epoll_ctl删除事件
        _linkMap.erase(sockfd);
        close(sockfd);
        link_ptr->_sockfd = -1; //将链接置为无效
    }

    std::shared_ptr<Link> GetLink(int sockfd)
    {
        return _linkMap[sockfd];
    }

    void PrintLinks()
    {
        // 打印一下ip:port, sockfd, recv_q, send_q（读写缓冲区size）
        std::cout << "Foreign Address" << TAB8 << "Sockfd" << TAB8 << "Recv_Q" << TAB8 << "Send_Q" << std::endl;
        for (auto [sockfd, link_ptr] : _linkMap)
        {
            // std::cout << link_ptr->_ip << ":" << link_ptr->_port << TAB << link_ptr->_sockfd << TAB
            //           << link_ptr->_inbuf.size() << TAB << link_ptr->_outbuf.size();
            std::stringstream sstream;
            sstream << link_ptr->_ip << ":" << link_ptr->_port;
            // std::cout << link_ptr->_ip << std::endl;
            printf("%-21s  %-6d%s%-6ld%s%-6ld\n", sstream.str().c_str(),
                   link_ptr->_sockfd, TAB8, link_ptr->_inbuf.size(), TAB8, link_ptr->_outbuf.size());
        }
        std::cout << std::endl;
    }
};

void Link::ModEvent(uint32_t event)
{
    _linkmng._epoller.EpollCtrl(EPOLL_CTL_MOD, _sockfd, event);
    _event = event;
}
